Skip to content

一、AHT30温湿度传感器

内容在上一级目录。

如果无法预览,请点击 此处下载 AHT30温湿度传感器说明书A0-0417 PDF 文件

二、ESP-IDF如何编写I2C驱动读取AHT30温湿度数据(简洁版)?

c
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/i2c_master.h"  // 引入新版 I2C 主机驱动头文件

// 定义 I2C 引脚和参数
#define I2C_MASTER_SCL_IO   5        // SCL(时钟线)连接的 GPIO 引脚号
#define I2C_MASTER_SDA_IO   6        // SDA(数据线)连接的 GPIO 引脚号
#define AHT30_I2C_ADDR      0x38     // AHT30 传感器的 7 位 I2C 地址(固定为 0x38)
#define I2C_MASTER_FREQ_HZ  100000   // I2C 总线时钟频率:100kHz(标准模式)

static const char *TAG = "AHT30";   // 日志标签,打印日志时会显示 "AHT30"

// AHT30 的初始化命令:0xBE 是命令字,0x08 和 0x00 是参数
// 上电后需要先发送此命令,让传感器进入正常工作状态
static const uint8_t AHT30_CMD_INIT[]    = {0xBE, 0x08, 0x00};

// AHT30 的触发测量命令:0xAC 是命令字,0x33 和 0x00 是参数
// 每次想要获取温湿度数据前,都需要先发送此命令触发一次测量
static const uint8_t AHT30_CMD_TRIGGER[] = {0xAC, 0x33, 0x00};

void app_main(void)
{
    // =========================================================
    // 第一步:配置并初始化 I2C 主机总线
    // =========================================================
    // i2c_master_bus_config_t 是总线配置结构体,描述这条 I2C 总线的硬件参数
    i2c_master_bus_config_t i2c_mst_config = {
        .clk_source = I2C_CLK_SRC_DEFAULT,      // 使用默认时钟源
        .i2c_port = I2C_NUM_0,                  // 使用 ESP32-S3 的 I2C 端口 0
        .scl_io_num = I2C_MASTER_SCL_IO,        // 指定 SCL 引脚(GPIO5)
        .sda_io_num = I2C_MASTER_SDA_IO,        // 指定 SDA 引脚(GPIO6)
        .glitch_ignore_cnt = 7,                 // 毛刺过滤:忽略小于 7 个时钟周期的干扰信号
        .flags.enable_internal_pullup = true,   // 启用芯片内部上拉电阻(省去外接上拉电阻)
    };

    i2c_master_bus_handle_t bus_handle;  // 总线句柄,后续操作都需要用到它
    // i2c_new_master_bus() 根据上面的配置,初始化 I2C 总线,并返回总线句柄
    // ESP_ERROR_CHECK() 会检查函数返回值,如果出错则打印错误信息并重启
    ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));

    // =========================================================
    // 第二步:将 AHT30 设备挂载到 I2C 总线上
    // =========================================================
    // i2c_device_config_t 是设备配置结构体,描述挂载在总线上的某个从机设备
    i2c_device_config_t dev_cfg = {
        .dev_addr_length = I2C_ADDR_BIT_LEN_7,  // AHT30 使用 7 位地址模式
        .device_address = AHT30_I2C_ADDR,       // AHT30 的 I2C 地址:0x38
        .scl_speed_hz = I2C_MASTER_FREQ_HZ,     // 与该设备通信时的 SCL 频率:100kHz
    };

    i2c_master_dev_handle_t dev_handle;  // 设备句柄,后续读写操作都通过它来指定目标设备
    // i2c_master_bus_add_device() 将 AHT30 设备注册到总线,返回设备句柄
    ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));

    // =========================================================
    // 第三步:发送初始化命令,让 AHT30 进入正常工作状态
    // =========================================================
    // i2c_master_transmit() 向从机发送数据(写操作)
    // 参数:设备句柄、要发送的数据指针、数据长度、超时时间(-1 表示永久等待)
    ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, AHT30_CMD_INIT, sizeof(AHT30_CMD_INIT), -1));

    // 等待 100ms,让 AHT30 完成初始化
    vTaskDelay(pdMS_TO_TICKS(100));

    // =========================================================
    // 主循环:每隔 2 秒读取一次温湿度数据
    // =========================================================
    while (1) {
        // 第四步:发送触发测量命令,通知 AHT30 开始采集温湿度
        ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, AHT30_CMD_TRIGGER, sizeof(AHT30_CMD_TRIGGER), -1));

        // 第五步:等待 100ms,让 AHT30 完成测量(典型测量时间约 80ms)
        vTaskDelay(pdMS_TO_TICKS(100));

        // 第六步:从 AHT30 读取 6 字节的原始数据
        // AHT30 返回的 6 字节格式:
        //   data[0]:状态字节
        //   data[1]~data[2] 高 4 位:湿度原始值(共 20 位)
        //   data[2] 低 4 位~data[3]:温度/湿度交界
        //   data[3] 低 4 位~data[5]:温度原始值(共 20 位)
        uint8_t data[6] = {0};
        // i2c_master_receive() 从从机读取数据(读操作)
        // 参数:设备句柄、存放数据的缓冲区、读取字节数、超时时间
        ESP_ERROR_CHECK(i2c_master_receive(dev_handle, data, sizeof(data), -1));

        // =========================================================
        // 第七步:解析原始数据,转换为实际温湿度值
        // =========================================================

        // 湿度原始值(20位):
        //   data[1] 的全部 8 位作为高位
        //   data[2] 的全部 8 位作为中间位
        //   data[3] 的高 4 位作为低位
        // 通过位移和或运算拼接成 20 位整数
        uint32_t humidity_raw = ((uint32_t)data[1] << 12)   // data[1] 左移 12 位
                              | ((uint32_t)data[2] << 4)    // data[2] 左移 4 位
                              | (data[3] >> 4);             // data[3] 右移 4 位取高 4 位

        // 温度原始值(20位):
        //   data[3] 的低 4 位作为高位
        //   data[4] 的全部 8 位作为中间位
        //   data[5] 的全部 8 位作为低位
        uint32_t temperature_raw = (((uint32_t)data[3] & 0x0F) << 16)  // data[3] 低4位左移16位
                                 | ((uint32_t)data[4] << 8)             // data[4] 左移 8 位
                                 | data[5];                             // data[5] 直接作为最低位

        // 将原始值转换为实际湿度(%RH)
        // 公式来自 AHT30 数据手册:湿度 = 原始值 / 2^20 * 100
        float humidity    = (float)humidity_raw    / 1048576.0f * 100.0f;

        // 将原始值转换为实际温度(°C)
        // 公式来自 AHT30 数据手册:温度 = 原始值 / 2^20 * 200 - 50
        float temperature = (float)temperature_raw / 1048576.0f * 200.0f - 50.0f;

        // 通过串口打印温湿度结果,%.2f 表示保留两位小数
        ESP_LOGI(TAG, "Temperature: %.2f °C, Humidity: %.2f %%", temperature, humidity);

        // 等待 2000ms(2秒)后再进行下一次测量
        vTaskDelay(pdMS_TO_TICKS(2000));
    }

    // =========================================================
    // 清理资源(注意:while(1) 永远不会退出,所以这里实际不会执行)
    // 如果将来改为有限循环,可以用这两行释放资源
    // =========================================================
    ESP_ERROR_CHECK(i2c_master_bus_rm_device(dev_handle));  // 从总线上移除设备
    ESP_ERROR_CHECK(i2c_del_master_bus(bus_handle));        // 删除 I2C 总线
}

觉醒,然后燎原。 © 2026 门主引擎